package manager

import (
	"encoding/json"
	"sync/atomic"
	"time"
)

type ClusterConfig struct {
	Node []ClusterConfigItem `json:"node" redis:"node"`
}

type ClusterConfigItem struct {
	ID      string `json:"id" redis:"id"`
	Address string `json:"address" redis:"address"`
}

func getClusterConfig() *ClusterConfig {

	for !mConfig.initFinished.Load() {
		time.Sleep(time.Millisecond * 200)
	}
	return mConfig.clusterConfig
}

func setClusterConfig(data ClusterConfig) error {

	mConfig.clusterConfig.merge(data.transfer())
	return mConfig.flushCluster()
}

func (t *ClusterConfig) sync(data *clusterConfigSync) {

	t.Node = data.Node
}

func (t *ClusterConfig) merge(data *clusterConfigSync) *ClusterConfig {

	var m = make(map[string]int)
	for i, v := range t.Node {
		m[v.ID] = i
	}

	var nodes []ClusterConfigItem
	for _, v := range data.Node {
		if i, ok := m[v.ID]; ok {
			t.Node[i].Address = v.Address
		} else {
			nodes = append(nodes, ClusterConfigItem{
				ID:      v.ID,
				Address: v.Address,
			})
		}
	}
	if len(nodes) != 0 {
		t.Node = append(t.Node, nodes...)
	}

	return t
}

func (t *ClusterConfig) transfer() *clusterConfigSync {

	return &clusterConfigSync{
		Node: t.Node,
	}
}

type clusterConfigSync struct {
	Node []ClusterConfigItem `json:"node" redis:"node"`
}

func (c *clusterConfigSync) string() string {

	b, _ := json.Marshal(c)
	return string(b)
}

type clusterData interface {
	Merge(interface{})
}

type atomicData struct {
	*atomic.Int32
}

func (a *atomicData) Merge(data interface{}) {

	d := data.(*atomicData)
	a.Add(d.Load())
}
